package org.eclipse.wst.server.preview.openejb.jetty.loader;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.net.URLDecoder;

import org.mortbay.jetty.webapp.WebAppClassLoader;
import org.mortbay.jetty.webapp.WebAppContext;

/**JettyEmbedder : This class has just one public method that 
 * is public static void embed( ClassLoader jettyServerLoader ). 
 * The single method of this class loads and creates a instance 
 * of WebAppClassLoader using the jettyServerLoader. After that, 
 * WebAppClassLoader is used to load and init the class responsible 
 * to run the OpenEJB container under the ClassLoader hierarchy 
 * of Jetty web server. That is made calling the init method of 
 * the class JettyHook, not before of the addition of OpenEJB 
 * loader dependencies in the WebAppClassLoader classpath. 
 * 
 * @author Marcelo de Oliveira Dias
 *
 */
public class JettyEmbedder {

	/**Creates a WebAppContext to instantiate and deploy a OpenEJB container into it. 
	 * 
	 * @param jettyServerLoader
	 */
	public static void embed() {
		
        try {
        	// create a WebAppClassLoader and a WebAppContext to hold OpenEJB.
        	WebAppContext webAppContext = new WebAppContext();
        	WebAppClassLoader webAppClassLoader = new WebAppClassLoader(ClassLoader.getSystemClassLoader(), webAppContext);
        	
        	// Put this jar into the new WebAppClassLoader classpath that will load OpenEJB. 
            File thisJar = getThisJar();
            String thisJarUrl = thisJar.toURI().toString();
            webAppClassLoader.addClassPath(thisJarUrl);
            
            // The property "openejb.webapp" tells where the openejb.war was unziped by the JettyServer.
            // This is set in "PreviewStarted" class.
            String openejbWebapp = System.getProperty("openejb.webapp");
            // Put the "openejb-loader" jar into the new WebAppClassLoader classpath
            String loaderPath = openejbWebapp + "/WEB-INF/lib/openejb-loader-3.1.1.jar";
            webAppClassLoader.addClassPath(loaderPath);
            
            // Use new classLoader created to load the JettyHookClass
//            JettyHook.hook();
            Class<?> hookClass = webAppClassLoader.loadClass("org.eclipse.wst.server.preview.openejb.jetty.loader.JettyHook");
            Method hookMethod = hookClass.getDeclaredMethod("hook");
            hookMethod.setAccessible(true);
            hookMethod.invoke(null);
            
        } catch (Exception e)  {
        	e.printStackTrace();
        }
		
	}
	
	/**Creates a File based with the path of the jar that contains this class.
	 * 
	 * @return the file created.
	 */
	private static File getThisJar() {
        return jarLocation( JettyEmbedder.class );
    }

	/**Creates a File from the path of the jar file which has the class "clazz". 
	 * 
	 * @param clazz 
	 * @return a File: - This File will be created based on the path of the jar which contains class "clazz". 
	 */
    private static File jarLocation(Class<?> clazz) {
        try {
            String classFileName = clazz.getName().replace(".", "/") + ".class";

            URL classURL = clazz.getClassLoader().getResource(classFileName);

            URI uri = null;
            String url = classURL.toExternalForm();
            if (url.contains("+")) {
                url = url.replaceAll("\\+", "%2B");
            }

            if (url.contains(" ")) {
                url = url.replaceAll(" ", "%20");
            }
            uri = new URI(url);

            if (uri.getPath() == null){
                uri = new URI(uri.getRawSchemeSpecificPart());
            }

            String path = uri.getPath();
            if (path.contains("!")){
                path = path.substring(0, path.indexOf('!'));
            } else {
                path = path.substring(0, path.length() - classFileName.length());
            }

            path = path.replaceAll("\\+", "%2B");
                   
            return new File(URLDecoder.decode(path));
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }
}
